package peace.htmllooker.node.table
{
import flash.text.StyleSheet;

import peace.htmllooker.Box;
import peace.htmllooker.HtmlUtils;
import peace.htmllooker.Node;

import peace.gui.layout.MultipleRowLayout;

/**
 * 
 *  
 */
public class Table extends Box
{
	/**
	 * матрица ячеек 
	 */	
	protected var cells:Array = [];
	
	protected var cellpadding:Number = 2;
	protected var cellspacing:Number = 3;
	
	public function Table(xml:XML, css:StyleSheet)
	{
		super(xml, css);
	}

	override protected function init(xml:XML, css:StyleSheet):void
	{
		// зачения по умолчанию
		hasBorder = false;
		
		// читаем свойства
		if (xml.@align != undefined) align = xml.@align;
		if (xml.@border != undefined) 
		{
			hasBorder = Boolean(xml.@border) && int(xml.@border) > 0;
			borderThickness = xml.@border;
			
			if (xml.@bordercolor != undefined)
			{
				borderColor = HtmlUtils.htmlColor_To_0xcolor(xml.@bordercolor);
			}
		}
		if (xml.@bgcolor != undefined) 
		{
			hasBackground = true;
			backgroundColor = HtmlUtils.htmlColor_To_0xcolor(xml.@bgcolor);
		}
		if (xml.@cellpadding != undefined) cellpadding = xml.@cellpadding;
		if (xml.@cellspacing != undefined) cellspacing = xml.@cellspacing;

		var styles:Object;
		var s:String;
		if (xml.@style != undefined)
		{
			styles = parseStyleAttribute(xml.@style);
		}
		if (xml.@width != undefined || (styles && styles.width))
		{
			s = styles ? styles.width : xml.@width;
			if (s.indexOf("%") > -1) percentWidth = parseFloat(s)
			else explicitWidth = parseFloat(s);
		}
		if (xml.@height != undefined || (styles && styles.height))
		{
			s = styles ? styles.height : xml.@height;
			if (s.indexOf("%") > -1) percentHeight = parseFloat(s)
			else explicitHeight = parseFloat(s);
		}
		
		padding.leftRight = padding.topBottom = cellspacing/2;

		container.layout = new MultipleRowLayout();

		super.init(xml, css);
		
	}
	/**
	 * 
	 * @param xml
	 * @param css
	 * 
	 */	
	override protected function createChildren(xml:XML, css:StyleSheet):void
	{
		if (xml.*[0].localName() == "tbody")
		{
			xml = xml.*[0];
		}
		var cell:Cell;
		// <table>
		for each (var i:XML in xml.*)
		{
			// для каждой строки новый массив
			cells[i.childIndex()] = [];
			//<tr>
			for each (var j:XML in i.*)
			{
				cell = new Cell(j, css, cellpadding, cellspacing, 
							(hasBorder) ? borderThickness : 0, borderColor, align);
				cells[i.childIndex()][j.childIndex()] = cell;
				container.add(cell);
			}
			// </tr>
		}
		// </table>
	}
	
	/**
	 * Только после выравнивания можно явно понять, 
	 * что размеры таблицы изменились.
	 */	
	override public function arrange():void
	{
		if (! needArrange) return;
		if (cells.length == 0) return;
		
		var w:Number = explicitWidth - cellspacing || 0; 
		var h:Number = explicitHeight - cellspacing || 0; 
		
		// выравниваем ячейки
		var n:Node;
		for each (n in container.children)
		{
			n.arrange();
		}
		
		var arr:Array;
		// вычисляем ширину столбцов 
		var widths:DimensionsArray = new DimensionsArray(w, cellspacing);
		for (var i:int = 0; i < cells[0].length; i++)
		{
			widths.push (getColumnWidth(i));
		}
		arr = widths.calculateDimensions();
		
		// Если w==0 (размер не указан пользователем), НО размер родителя меньше 
		// результата вычислений, стараемся привести к размеру родителя. 
		// Для случая widths.size < parentBox.width не делаем ничего
		var p:Box = parentBox;
		if (w == 0 && p && p.width - p.shellWidth < widths.size)
		{
			explicitWidth = p.width - p.shellWidth;
			widths.size = explicitWidth - cellspacing;
			arr = widths.calculateDimensions();
		}
		
		// выставляем ширину столбцам
		w = 0;
		for (i = 0; i < arr.length; i++)
		{
			setColumnWidth(i, arr[i]);
			w += arr[i];
		}
		container.userWidth = w;

		// вычисляем высоту строк
		var heights:DimensionsArray = new DimensionsArray(h, cellspacing);
		for (i = 0; i < cells.length; i++)
		{
			heights.push (getRowHeight(i));
		}
		arr = heights.calculateDimensions();
		
		// выставляем высоту строкам
		h = 0;
		for (i = 0; i < arr.length; i++)
		{
			setRowHeight(i, arr[i]);
			h += arr[i];
		}
		container.userHeight = h;
		
		// снова выравниваем ячейки
		for each (n in container.children)
		{
			n.arrange();
		}

		container.arrange();

		needArrange = false;

		// выставляем размеры
		minWidth = widths.min + shellWidth;
		preferredWidth = widths.preferred + shellWidth;
		minHeight = heights.min + shellHeight;
		preferredHeight = heights.preferred + shellHeight;

		super.arrange();
	}
	/**
	 * Меряем высоту строки таблицы 
	 * 
	 * @param index
	 * @param tableHeight Number предполагаемая высота таблицы
	 * @return 
	 * 
	 */	
	protected function getRowHeight (index:int):TableDimensions
	{
		var d:TableDimensions = new TableDimensions();
		var arr:Array = cells[index];
		var h:Number;
		for each (var c:Cell in arr)
		{
			d.min = Math.max(d.min, c.minHeight);
			d.preferred = Math.max(d.preferred, c.preferredHeight);
			d.pixel = c.explicitHeight ? Math.max(d.pixel || 0, c.explicitHeight) : d.pixel;
			d.percent = c.percentHeight ? Math.max(d.percent || 0, c.percentHeight) : d.percent;
		}
		return d;
	}
	/**
	 * Выставляем высоту строке
	 * 
	 * @param index int индекс строки
	 * @param value Number высота
	 * 
	 */	
	protected function setRowHeight (index:int, value:Number):void
	{
		var arr:Array = cells[index];
		for each (var c:Cell in arr)
		{
			c.height = value;
		}
	}
	/**
	 * Меряем ширину столбца
	 *  
	 * @param index
	 * @param tableWidth Number предполагаемая ширина таблицы
	 * @return 
	 * 
	 */	
	protected function getColumnWidth (index:int):TableDimensions
	{
		var d:TableDimensions = new TableDimensions();
		var c:Cell;
		var w:Number;
		for each (var arr:Array in cells)
		{
			c = Cell (arr[index]);
			d.min = Math.max(d.min, c.minWidth);
			d.preferred = Math.max(d.preferred, c.preferredWidth);
			d.pixel = c.explicitWidth ? Math.max(d.pixel || 0, c.explicitWidth) : d.pixel;
			d.percent = c.percentWidth ? Math.max(d.percent || 0, c.percentWidth) : d.percent;
		}
		return d;
	}
	/**
	 * Выставляем ширину столбцу 
	 * 
	 * @param index int индекс столбца
	 * @param value Number ширина
	 * 
	 */	
	protected function setColumnWidth (index:int, value:Number):void
	{
		var c:Cell;
		for each (var arr:Array in cells)
		{
			c = Cell (arr[index]);
			c.width = value;
			
			// выравниваем, если изменилась высота
			c.arrange();
		}
	}
	/**
	 * @private
	 * 
	 * таблица ресайзится автономно, на основании своих параметров <br>
	 * если не указан percentWidth
	 */	
	override public function set width(value:Number):void
	{
		// если размеры процентные, то считаем размер
		if (percentWidth)
		{
			// тупо выставляем explicitWidth
			explicitWidth = percentWidth/100 * value;
			needArrange = true;
		}
		// иначе выставляем принудительный размер только в случае
		// если родитель - ячейка таблицы
		else if (parentBox is Cell)
		{
			explicitWidth = value;
			needArrange = true;
		}
		// Если размер меньше текущего, нужно попытаться к нему привести.
		// Если больше, то это не explicitWidth
		else if (value < width)
		{
			explicitWidth = value;
			needArrange = true;
		}
	}
	/**
	 * @private
	 * 
	 * таблица ресайзится автономно, на основании своих параметров 
	 * и параметров строк и ячеек
	 */	
	override public function set height(value:Number):void
	{
		// если размеры процентные, то считаем размер
		if (percentHeight)
		{
			explicitHeight = value;
			needArrange = true;
		}
	}
	
	

	
}
}